#ifndef _READRESULT_H_
#define _READRESULT_H_ 1

#include "kernel/dll_cfg.h"
#include "kernel/string_def.h"
#include "kernel/time/time.h"

namespace FD
{
	namespace Kernel
	{
		/**
		* String wrapped in an osg::Object (for I/O purposes)
		*/
		class /*FD_Kernel_Export*/ StringObject : public FD::Kernel::CReferenced/*Object*/
		{
		public:
			StringObject();
			//StringObject( const StringObject& rhs, const CopyOp& op ) : Object(rhs, op), _str(rhs._str) { }
			//StringObject( const std::string& in ) : Object(), _str(in) { }

			/** dtor */
			virtual ~StringObject() {};
			//META_Object( "Fd.XKernel", StringObject );

			void setString( const std::string& value ) {_str = value;};
			const std::string& getString() const {return _str;};
		private:
			std::string _str;
		};
		/**
		* Return value from a read* method
		*/
		struct FD_Kernel_Export ReadResult
		{
			/** Read result codes. */
			enum Code
			{
				RESULT_OK,
				RESULT_CANCELED,
				RESULT_NOT_FOUND,
				RESULT_EXPIRED,
				RESULT_SERVER_ERROR,
				RESULT_TIMEOUT,
				RESULT_NO_READER,
				RESULT_READER_ERROR,
				RESULT_UNKNOWN_ERROR,
				RESULT_NOT_IMPLEMENTED,
				RESULT_NOT_MODIFIED
			};

			/** Construct a result with no object */
			ReadResult( Code code =RESULT_NOT_FOUND )
				: _code(code), _fromCache(false), _lmt(0) { }

			/** Construct a result with code and data */
			ReadResult( Code code, CReferenced/*Object*/* result )
				: _code(code), _result(result), _fromCache(false), _lmt(0) { }

			/** Construct a result with data, possible with an error code */
			ReadResult( Code code, CReferenced/*Object*/* result, const String& meta )
				: _code(code), _result(result), _meta(meta), _fromCache(false), _lmt(0) { }

			/** Construct a successful result (implicit OK code) */
			ReadResult( CReferenced/*Object*/* result )
				: _code(RESULT_OK), _result(result), _fromCache(false), _lmt(0) { }

			/** Construct a successful result with metadata */
			ReadResult( CReferenced/*Object*/* result, const String& meta )
				: _code(RESULT_OK), _result(result), _meta(meta), _fromCache(false), _lmt(0) { }

			/** Copy construct */
			ReadResult( const ReadResult& rhs )
				: _code(rhs._code), _result(rhs._result.get()), _meta(rhs._meta), _fromCache(rhs._fromCache), _lmt(rhs._lmt) { }

			/** dtor */
			virtual ~ReadResult() { }

			/** Whether the read operation succeeded */
			bool succeeded() const { return _code == RESULT_OK && _result.valid(); }

			/** Whether the read operation failed */
			bool failed() const { return _code != RESULT_OK; }

			/** Whether the result contains an object */
			bool empty() const { return !_result.valid(); }

			/** Detail message, sometimes set upon error */
			const std::string& errorDetail() const { return _detail; }

			/** The result code */
			const Code& code() const { return _code; }

			/** Last modified timestamp */
			TimeStamp lastModifiedTime() const { return _lmt; }

			/** Duration of request/response in seconds */
			double duration() const { return _duration_s; }

			/** True if the object came from the cache */
			bool isFromCache() const { return _fromCache; }

			/** The result */
			CReferenced/*Object*/* getObject() const { return _result.get(); }

			/** The result, transfering ownership to the caller */
			CReferenced/*Object*/* releaseObject() { return _result.release(); }

			/** The metadata */
			const String& metadata() const { return _meta; }

			/** The result, cast to a custom type */
			template<typename T>
			T* get() const { return dynamic_cast<T*>(_result.get()); }

			/** The result, cast to a custom type and transfering ownership to the caller*/
			template<typename T>
			T* release() { return dynamic_cast<T*>(_result.get())? static_cast<T*>(_result.release()) : 0L; }

			/** The result as a string */
			const std::string& getString() const { const StringObject* so = dynamic_cast<StringObject*>(_result.get()); return so ? so->getString() : _emptyString; }

			/** Gets a string describing the read result */
			static std::string getResultCodeString( unsigned code )
			{
				return
					code == RESULT_OK              ? "OK" :
					code == RESULT_CANCELED        ? "Read canceled" :
					code == RESULT_NOT_FOUND       ? "Target not found" :
					code == RESULT_SERVER_ERROR    ? "Server reported error" :
					code == RESULT_TIMEOUT         ? "Read timed out" :
					code == RESULT_NO_READER       ? "No suitable ReaderWriter found" :
					code == RESULT_READER_ERROR    ? "ReaderWriter error" :
					code == RESULT_NOT_IMPLEMENTED ? "Not implemented" :
					"Unknown error";
			}

			std::string getResultCodeString() const
			{
				return getResultCodeString( _code );
			}

		public:
			void setIsFromCache(bool value) { _fromCache = value; }

			void setLastModifiedTime(TimeStamp t) { _lmt = t; }

			void setDuration(double s) { _duration_s = s; }

			void setMetadata(const String& meta) { _meta = meta; }

			void setErrorDetail(const std::string& value) { _detail = value; }

		protected:
			Code                      _code;
			ref_ptr<CReferenced/*Object*/> _result;
			String                    _meta;
			std::string               _emptyString;
			String                    _emptyConfig;
			bool                      _fromCache;
			TimeStamp                 _lmt;
			double                    _duration_s;
			std::string               _detail;
		};
	}
}
#endif